package com.maimao.goods.service;

import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.maimao.core.constant.Constants;
import com.maimao.core.constant.ListData;
import com.maimao.core.constant.RedisKeys;
import com.maimao.core.exception.MaiMaoDaoException;
import com.maimao.core.model.resp.PageResult;
import com.maimao.core.model.resp.Result;
import com.maimao.core.utils.DateUtils;
import com.maimao.goods.client.OrderClient;
import com.maimao.goods.client.ShopClient;
import com.maimao.goods.client.UploadClient;
import com.maimao.goods.mapper.GoodsSkuMapper;
import com.maimao.goods.utils.HotWordUtil;
import com.maimao.mg.repository.CommentRepository;
import com.maimao.model.echarts.enums.CommentAggTimeType;
import com.maimao.model.echarts.common.*;
import com.maimao.model.goods.Comment;
import com.maimao.model.goods.GoodsSku;
import com.maimao.model.goods.dto.CommentAggDto;
import com.maimao.model.goods.dto.CommentTypeAggDto;
import com.maimao.model.goods.enums.CommentType;
import com.maimao.model.goods.input.CommentFilter;
import com.maimao.model.goods.input.CommentInput;
import com.maimao.model.goods.vo.CommentSingle;
import com.maimao.model.order.input.CommentStatusUpdateInput;
import com.maimao.model.user.Shop;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.maimao.model.echarts.common.SeriesTypeEnum.PIE;


/**
 * @author MaoLin Wang
 * @date 2021/1/28 11:12 上午
 */
@Service
public class CommentService {

    @Autowired
    private CommentRepository commentRepository;

    @Autowired
    private OrderClient orderClient;

    @Autowired
    private UploadClient uploadClient;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ShopClient shopClient;

    @Autowired
    private GoodsSkuMapper goodsSkuMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public Result saveComment(CommentInput input) {
        if (ObjectUtils.isNotEmpty(input.getRemoveImages())) {
            uploadClient.deleteBatch(input.getRemoveImages());

        }
        Result<Boolean> res = orderClient.commentStatus(CommentStatusUpdateInput.builder().orderId(input.getOrderId())
                .skuId(input.getSkuId()).build());
        if (res == null || res.getData() == null) {
            return Result.notValid("未查询到订单");
        }
        if (res.getData()) {
            return Result.notValid("您已评论过");
        }

        orderClient.updateComment(CommentStatusUpdateInput.builder().orderId(input.getOrderId())
                .skuId(input.getSkuId()).status(1).build());
        commentRepository.save(input);
        return Result.ok("评论成功");

    }

    /**
     * 详情页评论过滤
     *
     * @return
     */
    public Map<String, Object> queryByGoods(Long goodsId, CommentFilter filter, Integer page, Integer size) {
        Query query = new Query();
        Criteria criteria = Criteria.where("goods_id").is(goodsId).and("pid").is(0);

        if (filter.getHasPicture() != null && !filter.getHasPicture().equals(-1)) {
            criteria.and("has_picture").is(filter.getHasPicture());
        }
        if (filter.getType() != null && !filter.getType().equals(-1)) {
            criteria.and("type").is(filter.getType());
        }
        if (filter.getSkuId() != null && filter.getSkuId() >= 0) {
            criteria.and("sku_id").is(filter.getSkuId());
        }

        query.addCriteria(criteria);
        List<Comment> commentsC = mongoTemplate.find(query, Comment.class);
        //计算好评度
        String goodCommentPercent = computeGoodCommentPercent(commentsC);

        query.skip((page - 1) * size).limit(size);
        List<Comment> comments = mongoTemplate.find(query, Comment.class);


        if (ObjectUtils.isNotEmpty(comments)) {
            for (Comment comment : comments) {
                List<Comment> children = commentRepository.findCommentsByTopId(comment.getId());
                if (ObjectUtils.isNotEmpty(children) && children.size() > 3) {
                    children = children.subList(0, 3);
                }
                comment.setChildren(children);
            }
        }
        PageResult<Comment> commentPageResult = new PageResult<>(comments, (long) commentsC.size());
        Map<String, Object> res = Maps.newHashMapWithExpectedSize(2);
        res.put("data", commentPageResult);
        res.put("goodCommentPercent", goodCommentPercent);
        return res;
    }

    private String computeGoodCommentPercent(List<Comment> commentsC) {
        if (ObjectUtils.isNotEmpty(commentsC)) {
            //好评数量
            BigDecimal goodCommentCount = BigDecimal.valueOf(0);
            Map<Integer, List<Comment>> typeMap = commentsC.stream().collect(Collectors.groupingBy(Comment::getType));
            List<Comment> goodComments = typeMap.get(CommentType.GOOD.getType());
            if (ObjectUtils.isNotEmpty(goodComments)) {
                goodCommentCount = BigDecimal.valueOf(goodComments.size());
            }
            if (goodCommentCount.compareTo(BigDecimal.valueOf(0)) == 0) {
                return "0.00";
            }
            BigDecimal percentRes = goodCommentCount.divide(BigDecimal.valueOf(commentsC.size()), 2, RoundingMode.HALF_UP);
            return percentRes.doubleValue() * 100 + "";
        }
        return "0.00";
    }

    /**
     * 店铺评价中心查询评价
     */
    public PageResult<Comment> queryByShop(Long shopId, CommentFilter filter, Integer page, Integer size) {

        Query query = new Query();
        Criteria criteria = Criteria.where("shop_id").is(shopId).and("pid").is(0);

        if (filter.getHasPicture() != null && !filter.getHasPicture().equals(-1)) {
            criteria.and("has_picture").is(filter.getHasPicture());
        }
        if (filter.getType() != null && !filter.getType().equals(-1)) {
            criteria.and("type").is(filter.getType());
        }
        if (filter.getGoodsId() != null && filter.getGoodsId() >= 0) {
            criteria.and("goods_id").is(filter.getGoodsId());
        }
        if (filter.getOrderId() != null && filter.getOrderId() >= 0) {
            criteria.and("order_id").is(filter.getOrderId());
        }
        if (filter.getNeedExplain() != null && !filter.getNeedExplain().equals(-1)) {
            criteria.and("need_explain").is(filter.getNeedExplain());
        }

        query.addCriteria(criteria);
        long count = mongoTemplate.count(query, Comment.class);

        query.skip((page - 1) * size).limit(size);
        List<Comment> comments = mongoTemplate.find(query, Comment.class);
        if (ObjectUtils.isNotEmpty(comments)) {
            for (Comment comment : comments) {
                GoodsSku goodsSku = goodsSkuMapper.selectById(comment.getSkuId());
                if (goodsSku != null) {
                    comment.setSpec(goodsSku.getName());
                }
            }
        }
        return new PageResult<>(comments, count);


    }

    /**
     * 根据id查  只能是顶级评论
     *
     * @param id
     * @return
     */
    public CommentSingle queryById(Long id) {
        Comment comment = commentRepository.findCommentByIdAndPid(id, 0L);
        if (comment != null) {
            List<Comment> children = commentRepository.findCommentsByTopId(comment.getId());
            comment.setChildren(children);
        }
        Long skuId = comment.getSkuId();
        long num = mongoTemplate.count(new Query().addCriteria(Criteria.where("sku_id").is(skuId)), Comment.class);

        List<GoodsSku> goodsSkus = goodsSkuMapper.selectByIdsBatchValid(Lists.newArrayList(skuId));
        CommentSingle commentSingle = new CommentSingle();
        BeanUtils.copyProperties(comment, commentSingle);
        commentSingle.setCommentNum(num);
        if (ObjectUtils.isNotEmpty(goodsSkus)) {
            GoodsSku goodsSku = goodsSkus.get(0);
            if (!StringUtils.isEmpty(goodsSku.getPictures())) {
                List<String> pictureList = JSON.parseObject(goodsSku.getPictures(), List.class);
                if (goodsSku.getShowIndex() != null && goodsSku.getShowIndex() >= 0 && ObjectUtils.isNotEmpty(pictureList)) {
                    goodsSku.setPictures(pictureList.get(goodsSku.getShowIndex()));
                }
            }

            commentSingle.setGoodsSku(goodsSku);

        }
        return commentSingle;
    }

    //    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public Result<Void> replyComment(CommentInput input, Long loginUser) {
        Result<Shop> shopResult = shopClient.queryByIdIn(input.getShopId());
        if (shopResult == null || shopResult.getData() == null) {
            return Result.notValid("评论失败，店铺未找到或被冻结");
        }
        boolean isShop = false;
        if (shopResult.getData().getOwner().equals(loginUser)) {
            //回复人是商家
            input.setFromType(0);
            input.setAnonymous(0);
            isShop = true;
        } else {
            input.setFromType(1);
        }
        //判断当前用户是否为当前商品的商家
        input.setReplied(0);

        Comment comment = new Comment();
        BeanUtils.copyProperties(input, comment);
        commentRepository.save(comment);

        Long pid = comment.getPid();
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(pid));
        Update update = new Update();

        if (isShop) {
            Comment parentComment = mongoTemplate.findOne(query, Comment.class);
            if (parentComment != null && parentComment.getNeedExplain().equals(1)) {
                //如果父评论需要解释 且当前回复人为商家 ，则修改父评论的needExplain为2
                update.set("need_explain", 2);
            }
        }

        update.set("replied", 0);
        mongoTemplate.updateFirst(query, update, Comment.class);
        return Result.ok();
    }

    /**
     * 后台评论数据折线图
     *
     * @param aggTimeType
     * @return
     */
    public LineOption<Integer> line(Integer aggTimeType) {
        LineOption<Integer> lineOption = new LineOption<>();
        lineOption.setLegend(Arrays.asList("好评", "中评", "差评", "讨论", "全部"));
        List<EchartsOption.SeriesData<Integer>> seriesDataList = Lists.newArrayList();
        Map<Integer, Map<Integer, Integer>> typeDayMap = Maps.newHashMapWithExpectedSize(4);

        if (aggTimeType == null || aggTimeType.equals(CommentAggTimeType.DAY.getCode())) {
            //x轴
            lineOption.setXAxisData(DateUtils.getCurrentMonthDayStr());
            //按日
            // type -> dayMap
            typeDayMap.put(CommentType.GOOD.getType(), dayMap());
            typeDayMap.put(CommentType.NOT_GOOD.getType(), dayMap());
            typeDayMap.put(CommentType.BAD.getType(), dayMap());
            typeDayMap.put(CommentType.REPLY.getType(), dayMap());
            typeDayMap.put(CommentType.ALL.getType(), dayMap());

            this.getTypeDayMap(Aggregation.newAggregation(
                    Aggregation.match(Criteria.where("create_time").gte(DateUtils.firstDayOfMonth(-2))),
                    Aggregation.group("type", "createTime").count().as("count")
            ), typeDayMap, CommentAggTimeType.DAY);

        } else if (aggTimeType.equals(CommentAggTimeType.MONTH.getCode())) {
            lineOption.setXAxisData(DateUtils.get12MonthStr());
            // type -> dayMap
            typeDayMap.put(CommentType.GOOD.getType(), monthMap());
            typeDayMap.put(CommentType.NOT_GOOD.getType(), monthMap());
            typeDayMap.put(CommentType.BAD.getType(), monthMap());
            typeDayMap.put(CommentType.REPLY.getType(), monthMap());
            typeDayMap.put(CommentType.ALL.getType(), monthMap());

            this.getTypeDayMap(Aggregation.newAggregation(
                    Aggregation.match(Criteria.where("create_time").gte(DateUtils.firstDayOfYear())),
                    Aggregation.group("type", "createTime").count().as("count")
            ), typeDayMap, CommentAggTimeType.MONTH);
        } else if (aggTimeType.equals(CommentAggTimeType.YEAR.getCode())) {
            int pre10Year = DateUtils.now().plusYears(-10).getYear();
            lineOption.setXAxisData(DateUtils.getPreYearStr(pre10Year));

            typeDayMap.put(CommentType.GOOD.getType(), yearMap(pre10Year));
            typeDayMap.put(CommentType.NOT_GOOD.getType(), yearMap(pre10Year));
            typeDayMap.put(CommentType.BAD.getType(), yearMap(pre10Year));
            typeDayMap.put(CommentType.REPLY.getType(), yearMap(pre10Year));
            typeDayMap.put(CommentType.ALL.getType(), yearMap(pre10Year));


            this.getTypeDayMap(Aggregation.newAggregation(
                    //10年内的数据
                    Aggregation.match(Criteria.where("create_time").gte(DateUtils.now().plusYears(-10))),
                    Aggregation.group("type", "createTime").count().as("count")
            ), typeDayMap, CommentAggTimeType.YEAR);

        }
        boolean otherSeries = false;
        for (Map.Entry<Integer, Map<Integer, Integer>> entry : typeDayMap.entrySet()) {
            Integer type = entry.getKey();
            Map<Integer, Integer> dayMap = entry.getValue();
            EchartsOption.SeriesData<Integer> seriesData = new EchartsOption.SeriesData<>();
            seriesData.setType(SeriesTypeEnum.LINE.getType());
            String name = CommentType.getMsgByCode(type);
            otherSeries = StrUtil.isEmpty(name);
            seriesData.setName(otherSeries ? "其他" : name);
            seriesData.setData(otherSeries ? Lists.newArrayList() : Lists.newLinkedList(dayMap.values()));
            seriesDataList.add(seriesData);

        }
        if (otherSeries) {
            List<String> legend = lineOption.getLegend();
            legend.add("其他");
            lineOption.setLegend(legend);
        }
        lineOption.setSeries(seriesDataList);

        return lineOption;
    }

    private Map<Integer, Map<Integer, Integer>> getTypeDayMap(Aggregation aggregation, Map<Integer, Map<Integer, Integer>> typeDayMap, CommentAggTimeType aggTimeType) {
        AggregationResults<CommentTypeAggDto> typeAggRes = mongoTemplate.aggregate(aggregation, Comment.class, CommentTypeAggDto.class);
        Map<Integer, Integer> allMapData = typeDayMap.get(CommentType.ALL.getType());

        for (CommentTypeAggDto typeAggRe : typeAggRes) {
            Map<Integer, Integer> dayMapData = typeDayMap.get(typeAggRe.getType());
            if (aggTimeType.equals(CommentAggTimeType.YEAR)) {
                Integer count = dayMapData.get(typeAggRe.getCreateTime().getYear());
                Integer allCount = allMapData.get(typeAggRe.getCreateTime().getYear());
                if (count == null) {
                    count = 0;
                }
                if (allCount == null) {
                    allCount = 0;
                }
                allMapData.put(typeAggRe.getCreateTime().getYear(), allCount + typeAggRe.getCount());
                dayMapData.put(typeAggRe.getCreateTime().getYear(), count + typeAggRe.getCount());
            } else if (aggTimeType.equals(CommentAggTimeType.MONTH)) {
                allMapData.put(typeAggRe.getCreateTime().getMonthValue(), allMapData.get(typeAggRe.getCreateTime().getMonthValue()) + typeAggRe.getCount());
                dayMapData.put(typeAggRe.getCreateTime().getMonthValue(), dayMapData.get(typeAggRe.getCreateTime().getMonthValue()) + typeAggRe.getCount());
            } else if (aggTimeType.equals(CommentAggTimeType.DAY)) {
                allMapData.put(typeAggRe.getCreateTime().getDayOfMonth(), allMapData.get(typeAggRe.getCreateTime().getDayOfMonth()) + typeAggRe.getCount());
                dayMapData.put(typeAggRe.getCreateTime().getDayOfMonth(), dayMapData.get(typeAggRe.getCreateTime().getDayOfMonth()) + typeAggRe.getCount());
            }
            typeDayMap.put(typeAggRe.getType(), dayMapData);
        }
        typeDayMap.put(CommentType.ALL.getType(), allMapData);
        return typeDayMap;
    }

    private Map<Integer, Integer> yearMap(int preYear) {
        Map<Integer, Integer> dayMap = Maps.newLinkedHashMap();
        for (int i = preYear; i <= preYear + 10; i++) {
            dayMap.put(i, 0);
        }
        return dayMap;
    }

    private Map<Integer, Integer> monthMap() {
        Map<Integer, Integer> monthMap = Maps.newLinkedHashMap();
        for (int i = 1; i <= 12; i++) {
            monthMap.put(i, 0);
        }
        return monthMap;
    }

    /**
     * dayOfMonth->评论个数
     *
     * @return
     */
    private Map<Integer, Integer> dayMap() {
        Map<Integer, Integer> dayMap = Maps.newLinkedHashMap();

        for (int i = 1; i <= DateUtils.getToTalDayOfMonth(new Date()); i++) {
            dayMap.put(i, 0);
        }
        return dayMap;
    }


    /**
     * 后台评论数据概览 （内外圆饼图） 外饼图：好中差评总数 内环：带图和文字评论总数
     */
    public ChartsResult<Map<String, Object>> overview() {
        PieOption<Map<String, Object>> pieOption = new PieOption<>();
        pieOption.setLegend(Arrays.asList("好评", "中评", "差评", "讨论", "带图", "文字"));

        Aggregation typeAgg = Aggregation.newAggregation(
                Aggregation.group("type").count().as("count")
        );
        Aggregation hasPicture = Aggregation.newAggregation(
                Aggregation.group("hasPicture").count().as("count")
        );
        AggregationResults<CommentAggDto> typeAggRes = mongoTemplate.aggregate(typeAgg, Comment.class, CommentAggDto.class);
        AggregationResults<CommentAggDto> hasPictureRes = mongoTemplate.aggregate(hasPicture, Comment.class, CommentAggDto.class);
        long totalCount = mongoTemplate.findAll(Comment.class).size();
        long currentMonthCount = mongoTemplate.count(new Query().addCriteria(Criteria.where("create_time").gte(DateUtils.firstDayOfMonth())), Comment.class);
        long preMonthCount = mongoTemplate.count(new Query().addCriteria(Criteria.where("create_time").gte(DateUtils.firstDayOfMonth(-1))), Comment.class);

        //本月与上个月的环比 ((本-上)/上) * 100%
        long huanbi = preMonthCount == 0 ? 0 : (((currentMonthCount - preMonthCount) / preMonthCount) * 100);

        List<EchartsOption.SeriesData<Map<String, Object>>> seriesDataList = Lists.newLinkedList();
        Map<String, Boolean> typeExitMap = Maps.newHashMapWithExpectedSize(3);
        typeExitMap.put(CommentType.NOT_GOOD.name(), false);
        typeExitMap.put(CommentType.GOOD.name(), false);
        typeExitMap.put(CommentType.BAD.name(), false);
        typeExitMap.put(CommentType.REPLY.name(), false);


        Map<String, Boolean> picExistMap = Maps.newHashMapWithExpectedSize(3);
        picExistMap.put("picture", false);
        picExistMap.put("text", false);
        for (int i = 0; i < 2; i++) {
            if (i == 0) {
                //外环 好中差
                EchartsOption.SeriesData<Map<String, Object>> seriesData = new EchartsOption.SeriesData();
                seriesData.setName("评论类型");
                seriesData.setType(PIE.getType());
                List<CommentAggDto> mappedResults = typeAggRes.getMappedResults();
                List<Map<String, Object>> data = Lists.newArrayList();
                if (ObjectUtil.isNotEmpty(mappedResults)) {
                    for (CommentAggDto aggDto : mappedResults) {
                        HashMap<String, Object> map = Maps.newHashMapWithExpectedSize(2);

                        if (aggDto.getId().equals(CommentType.GOOD.getType())) {
                            map.put("name", "好评");
                            typeExitMap.put(CommentType.GOOD.name(), true);

                        } else if (aggDto.getId().equals(CommentType.BAD.getType())) {
                            map.put("name", "差评");
                            typeExitMap.put(CommentType.BAD.name(), true);
                        } else if (aggDto.getId().equals(CommentType.NOT_GOOD.getType())) {
                            map.put("name", "中评");
                            typeExitMap.put(CommentType.NOT_GOOD.name(), true);
                        } else if (aggDto.getId().equals(CommentType.REPLY.getType())) {
                            map.put("name", "讨论");
                            typeExitMap.put(CommentType.REPLY.name(), true);
                        }
                        map.put("value", aggDto.getCount());
                        data.add(map);
                    }
                    if (mappedResults.size() < 4) {
                        fillEmptyData(typeExitMap, data);
                    }
                    seriesData.setData(data);
                    seriesDataList.add(seriesData);

                } else {
                    fillEmptyData(typeExitMap, data);
                }
            } else {
                EchartsOption.SeriesData<Map<String, Object>> seriesData = new EchartsOption.SeriesData();
                seriesData.setName("图文类型");
                seriesData.setType(PIE.getType());
                List<CommentAggDto> mappedResults = hasPictureRes.getMappedResults();
                List<Map<String, Object>> data = Lists.newArrayList();
                if (ObjectUtil.isNotEmpty(mappedResults)) {
                    for (CommentAggDto aggDto : mappedResults) {
                        HashMap<String, Object> map = Maps.newHashMapWithExpectedSize(2);
                        if (aggDto.getId().equals(1)) {
                            map.put("name", "带图");
                            picExistMap.put("picture", true);

                        } else if (aggDto.getId().equals(0)) {
                            map.put("name", "文字");
                            picExistMap.put("text", true);
                        }
                        map.put("value", aggDto.getCount());
                        data.add(map);
                    }
                    if (mappedResults.size() < 2) {
                        if (!picExistMap.get("picture")) {
                            HashMap<String, Object> map = Maps.newHashMapWithExpectedSize(2);
                            map.put("picture", "带图");
                            map.put("value", 0);
                            data.add(map);
                        }
                        if (!picExistMap.get("text")) {
                            HashMap<String, Object> map = Maps.newHashMapWithExpectedSize(2);
                            map.put("text", "文字");
                            map.put("value", 0);
                            data.add(map);
                        }
                    }
                }
                seriesData.setData(data);
                seriesDataList.add(seriesData);
            }
            pieOption.setSeries(seriesDataList);

        }

        List<Object> other = Lists.newLinkedList();
        other.add(totalCount);
        other.add(currentMonthCount);
        other.add(preMonthCount);
        other.add(huanbi + "%");
        return new ChartsResult<>(pieOption, other);
    }

    private void fillEmptyData(Map<String, Boolean> typeExitMap, List<Map<String, Object>> data) {
        LinkedHashMap<String, CommentType> enumMap = EnumUtil.getEnumMap(CommentType.class);
        for (Map.Entry<String, Boolean> entry : typeExitMap.entrySet()) {
            if (!entry.getValue()) {
                Map<String, Object> map = Maps.newHashMapWithExpectedSize(2);
                map.put("name", enumMap.get(entry.getKey()).getDesc());
                map.put("value", 0);
                data.add(map);
            }
        }
    }

    /**
     * 店铺评价统计 7日内好中差的评价数 一个月内好中差的评价数 半年内好中差的评价数 累计评价数
     */
    public Map<String, Object> shopCommentAgg(Long shopId) {
        Aggregation sevenAgg = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("shopId").is(shopId).and("create_time").gte(LocalDateTime.now().plusDays(-7)).and("pid").is(0)),
                Aggregation.group("type").count().as("count")
        );
        Aggregation oneMonthAgg = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("shopId").is(shopId).and("create_time").gte(LocalDateTime.now().plusMonths(-1)).and("pid").is(0)),
                Aggregation.group("type").count().as("count")
        );
        Aggregation sixMonthAgg = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("shopId").is(shopId).and("create_time").gte(LocalDateTime.now().plusMonths(-6)).and("pid").is(0)),
                Aggregation.group("type").count().as("count")
        );
        Aggregation totalAgg = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("shopId").is(shopId)),
                Aggregation.group("type").count().as("count")
        );
        AggregationResults<CommentAggDto> sevenAggRes = mongoTemplate.aggregate(sevenAgg, Comment.class, CommentAggDto.class);
        AggregationResults<CommentAggDto> oneMonthAggRes = mongoTemplate.aggregate(oneMonthAgg, Comment.class, CommentAggDto.class);
        AggregationResults<CommentAggDto> sixMonthAggRes = mongoTemplate.aggregate(sixMonthAgg, Comment.class, CommentAggDto.class);
        AggregationResults<CommentAggDto> totalAggRes = mongoTemplate.aggregate(totalAgg, Comment.class, CommentAggDto.class);

        long totalCount = mongoTemplate.count(new Query(Criteria.where("shop_id").is(shopId)), Comment.class);
        /**
         *  key:good value 好评的 一周 一个月 半年内的数量
         *  key:notGoods value 中评的 一周 一个月 半年内的数量
         *  key:bad value 差评的 一周 一个月 半年内的数量
         *  key:totalAgg value 店铺累计各个类型的评价
         */
        Map<String, Object> res = Maps.newHashMapWithExpectedSize(4);
        List<CommentAggDto> sevenAggResults = sevenAggRes.getMappedResults();
        /*if (ObjectUtils.isNotEmpty(sevenAggResults)) {
            //一周的
            for (CommentAggDto dto : sevenAggResults) {
                if (dto.getId().equals(CommentType.GOOD.getType())) {
                    List<Integer> value = Lists.newArrayListWithCapacity(3);
                    value.add(dto.getCount() == null ? 0 : dto.getCount());
                    res.put(CommentType.GOOD.name(), value);
                } else if (dto.getId().equals(CommentType.NOT_GOOD.getType())) {
                    List<Integer> value = Lists.newArrayListWithCapacity(3);
                    value.add(dto.getCount() == null ? 0 : dto.getCount());
                    res.put(CommentType.NOT_GOOD.name(), value);
                } else if (dto.getId().equals(CommentType.BAD.getType())) {
                    List<Integer> value = Lists.newArrayListWithCapacity(3);
                    value.add(dto.getCount() == null ? 0 : dto.getCount());
                    res.put(CommentType.BAD.name(), value);
                }
            }
        } else {
            List<Integer> valueGood = Lists.newArrayListWithCapacity(3);
            valueGood.add(0);
            List<Integer> valueNotGood = Lists.newArrayListWithCapacity(3);
            valueNotGood.add(0);
            List<Integer> valueBAD = Lists.newArrayListWithCapacity(3);
            valueBAD.add(0);
            res.put(CommentType.GOOD.name(), valueGood);
            res.put(CommentType.NOT_GOOD.name(), valueNotGood);
            res.put(CommentType.BAD.name(), valueBAD);
        }*/
        getAggValue(sevenAggRes, res);
        getAggValue(oneMonthAggRes, res);
        getAggValue(sixMonthAggRes, res);
        res.put("total", totalCount);
        //累计统计
        if (ObjectUtils.isNotEmpty(totalAggRes)) {
            Map<String, Integer> totalMap = Maps.newHashMapWithExpectedSize(3);
            for (CommentAggDto dto : totalAggRes) {
                if (dto.getId().equals(CommentType.GOOD.getType())) {
                    totalMap.put(CommentType.GOOD.name(), dto.getCount());
                } else if (dto.getId().equals(CommentType.NOT_GOOD.getType())) {
                    totalMap.put(CommentType.NOT_GOOD.name(), dto.getCount());
                } else if (dto.getId().equals(CommentType.BAD.getType())) {
                    totalMap.put(CommentType.BAD.name(), dto.getCount());
                } else if (dto.getId().equals(CommentType.REPLY.getType())) {
                    totalMap.put(CommentType.REPLY.name(), dto.getCount());
                }
            }
            res.put("totalAgg", totalMap);
        }
        return res;

    }

    private void getAggValue(AggregationResults<CommentAggDto> oneMonthAggRes, Map<String, Object> res) {
        Map<String, Boolean> exitMap = Maps.newHashMapWithExpectedSize(3);
        exitMap.put(CommentType.NOT_GOOD.name(), false);
        exitMap.put(CommentType.GOOD.name(), false);
        exitMap.put(CommentType.BAD.name(), false);

        if (ObjectUtils.isNotEmpty(oneMonthAggRes) && ObjectUtils.isNotEmpty(oneMonthAggRes.getMappedResults())) {
            //一个月内的

            for (CommentAggDto dto : oneMonthAggRes) {
                if (dto.getId().equals(CommentType.GOOD.getType())) {
                    List<Integer> value = (List<Integer>) res.get(CommentType.GOOD.name());
                    value = initCapicity(value, oneMonthAggRes.getMappedResults().size());
                    value.add(dto.getCount() == null ? 0 : dto.getCount());
                    res.put(CommentType.GOOD.name(), value);
                    exitMap.put(CommentType.GOOD.name(), true);
                } else if (dto.getId().equals(CommentType.NOT_GOOD.getType())) {
                    List<Integer> value = (List<Integer>) res.get(CommentType.NOT_GOOD.name());
                    value = initCapicity(value, oneMonthAggRes.getMappedResults().size());
                    value.add(dto.getCount() == null ? 0 : dto.getCount());
                    res.put(CommentType.NOT_GOOD.name(), value);
                    exitMap.put(CommentType.NOT_GOOD.name(), true);
                } else if (dto.getId().equals(CommentType.BAD.getType())) {
                    List<Integer> value = (List<Integer>) res.get(CommentType.BAD.name());
                    value = initCapicity(value, oneMonthAggRes.getMappedResults().size());

                    value.add(dto.getCount() == null ? 0 : dto.getCount());
                    res.put(CommentType.BAD.name(), value);
                    exitMap.put(CommentType.BAD.name(), true);
                }
            }
        }
        if (ObjectUtils.isEmpty(oneMonthAggRes.getMappedResults())) {
            List<Integer> valueGood = (List<Integer>) res.get(CommentType.GOOD.name());
            valueGood= initCapicity(valueGood, oneMonthAggRes.getMappedResults().size());
            List<Integer> valueNotGood = (List<Integer>) res.get(CommentType.NOT_GOOD.name());
            valueNotGood=initCapicity(valueNotGood, oneMonthAggRes.getMappedResults().size());

            List<Integer> valueBad = (List<Integer>) res.get(CommentType.BAD.name());
            valueBad= initCapicity(valueNotGood, oneMonthAggRes.getMappedResults().size());

            valueGood.add(0);
            valueNotGood.add(0);
            valueBad.add(0);
            res.put(CommentType.GOOD.name(), valueGood);
            res.put(CommentType.NOT_GOOD.name(), valueNotGood);
            res.put(CommentType.BAD.name(), valueBad);
        } else if (oneMonthAggRes.getMappedResults().size() < 3) {
            for (Map.Entry<String, Boolean> entry : exitMap.entrySet()) {
                if (entry.getValue().equals(false)) {
                    List<Integer> value = (List<Integer>) res.get(entry.getKey());
                    value = initCapicity(value, oneMonthAggRes.getMappedResults().size());
                    value.add(0);
                    res.put(entry.getKey(), value);

                }
            }
        }
    }

    private List<Integer> initCapicity(List<Integer> list, int size) {
        if (ObjectUtil.isEmpty(list)) {
            return Lists.newArrayListWithCapacity(size);

        }
        return list;
    }

    /**
     * 店铺评论热词
     *
     * @param goodsId
     * @return
     */
    public List<Map<String, Object>> shopCommentHotWord(Long goodsId) {
        String key = String.format(RedisKeys.SHOP_COMMENT_HOT_KEY, goodsId);
        List<Map<String, Object>> res = redisTemplate.opsForList().range(key, 0, -1);
        if (ObjectUtils.isNotEmpty(res)) {
            return res;
        }
        Query query = new Query(Criteria.where("goods_id").is(goodsId));
        query.fields().include("content");
        List<Comment> comments = mongoTemplate.find(query, Comment.class);
        if (ObjectUtils.isNotEmpty(comments)) {
            List<String> contentList = comments.stream().map(Comment::getContent).collect(Collectors.toList());
            String contentAll = StringUtils.join(contentList, Constants.BLANK);
            res = HotWordUtil.wordFrequency(contentAll, 5);
            if(ObjectUtil.isNotEmpty(res)){
                redisTemplate.opsForList().rightPushAll(key, res);
                long timeout = 2 * RandomUtils.nextInt(1, 12);
                //过期时间：0到24小时
                redisTemplate.expire(key, timeout, TimeUnit.HOURS);
            }

            return res;
        }
        return ListData.EMPTY_LIST;
    }


}
